package cn.imvc.data.jpa.repository;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import cn.imvc.data.domain.ViewRequest;
import cn.imvc.data.util.JpqlUtil;
import cn.imvc.data.util.PageableUtil;

public class ISimpleJpaRepository<T, ID extends Serializable> extends
		SimpleJpaRepository<T, ID> implements IJpqlExecutor<T>, ISqlExecutor {
	private JpaEntityInformation<T, ?> entityInfo;
	private EntityManager entityManager;

	public ISimpleJpaRepository(Class<T> domainClass, EntityManager em) {
		this(JpaEntityInformationSupport.getMetadata(domainClass, em), em);
	}

	public ISimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation,
			EntityManager entityManager) {
		super(entityInformation, entityManager);
		this.entityInfo = entityInformation;
		this.entityManager = entityManager;
	}

	public Page<T> findAll(ViewRequest viewRequest) {
		if (viewRequest == null)
			viewRequest = new ViewRequest();
		return getPageImpl(viewRequest.getParams(),
				PageableUtil.toPageable(viewRequest));
	}

	private Page<T> getPageImpl(Map<String, String> params, Pageable pageable) {
		String jpql = "from " + entityInfo.getEntityName()
				+ JpqlUtil.toWhere(params);
		String orderBy = "";
		if (pageable.getSort() != null) {
			orderBy = " order by "
					+ pageable.getSort().toString().replaceAll(":", "");
		}
		Query query = entityManager.createQuery(jpql + orderBy);
		query.setFirstResult((pageable.getPageNumber() - 1)
				* pageable.getPageSize());
		query.setMaxResults(pageable.getPageSize());
		Long total = ((Long) entityManager.createQuery(
				"select count(*) " + jpql).setHint("org.hibernate.cacheable", true).getSingleResult()).longValue();
		
		query.setHint("org.hibernate.cacheable", true);
		@SuppressWarnings("unchecked")
		List<T> content = query.getResultList();
		return new PageImpl<T>(content, pageable, total);
	}

	public Page<T> findAll(String select, String from,
			ViewRequest viewRequest) {
		return getPageObject(select, from, viewRequest.getParams(),
				PageableUtil.toPageable(viewRequest));
	}

	private Page<T> getPageObject(String select, String from,
			Map<String, String> params, Pageable pageable) {
		String jpql = " from " + from + JpqlUtil.toWhere(params);
		String orderBy = "";
		if (pageable.getSort() != null) {
			orderBy = " order by "
					+ pageable.getSort().toString().replaceAll(":", "");
		}
		Query query = entityManager.createQuery("select " + select + jpql
				+ orderBy);
		query.setFirstResult((pageable.getPageNumber() - 1)
				* pageable.getPageSize());
		query.setMaxResults(pageable.getPageSize());
		Long total = ((Long) entityManager.createQuery(
				"select count("+select+") " + jpql).getSingleResult()).longValue();
		@SuppressWarnings("unchecked")
		List<T> content = query.getResultList();
		return new PageImpl<T>(content, pageable, total);
	}

	public <E> Page<E> findAll(Class<E> clazz, String select, String from,
			ViewRequest viewRequest) {
		// TODO Auto-generated method stub
		return null;
	}

	

}
